import sys
from typing import Annotated, Optional
from fastapi import Header, HTTPException, Request, Depends
from urllib import parse
import traceback
from redis import Redis
from sqlalchemy.orm import Session
from app.dependencies.db import get_db
from app.schemas.common_schema import RequestBody
from app.utils import biz_sign_util, bz_pay_util
from app import conf
from ..common.exceptions import GenericException
from ..common.enums.resp_enum import ErrTypes
from app.services import get_merc_key

import logging

logger = logging.getLogger(__name__)
key = '8a81609a885ae99a70f399548f34c2f5'

def on_permissions(request: Request = Depends()):
    pass

async def get_token_header(x_token: str = Header()):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")

async def parse_encryption_header(request: Request, 
                                params: RequestBody,
                                db: Annotated[Session, Depends(get_db)],
                                x_xpay_client_id: Annotated[str, Header()],
                                x_xpay_signature: Annotated[str, Header()],
                                x_algo_type: Optional[str] = Header(None)
                               ):
    logger.debug('>> parse_encryption_header')
    if not x_xpay_client_id or not x_xpay_signature:
        logger.error('请求头参数不完整')
        logger.info(f'x_xpay_client_id: {x_xpay_client_id}, x_xpay_signature: {x_xpay_signature}')
        raise GenericException(ErrTypes.validation_error, message='请求头参数不完整')
    else:
        enc_params = ''
        try:
            if request.method == 'GET':
                req_params = request.query_params
                enc_params = req_params.get('params')
            elif request.method == 'POST':
                req_params = await request.json()
                enc_params = req_params.get('params')
            else:
                raise GenericException('不支持的请求方法')
            # 验签, 解密
            merc_key_obj = get_merc_key(db, x_xpay_client_id)
            if merc_key_obj.status != 1:
                raise GenericException(ErrTypes.merc_key_invalid)
            secret_key = merc_key_obj.secret_key
            pay_util = bz_pay_util.BzPayUtil(secret_key=secret_key, 
                                             pri_key=merc_key_obj.pri_key, 
                                             pub_key=merc_key_obj.pub_key)
            #pay_util = bz_pay_util.BzPayUtil(secret_key=key)
            params = pay_util.decrypt_with_sm4(enc_params)
            if params:
                res = pay_util.verify_with_sm2(params, x_xpay_signature)
                if res:
                    return params
                else:
                    raise GenericException(ErrTypes.sign_validation_fail) 
                
            else:
                logger.error('参数解密错误, Error: %s' % err)
                raise GenericException(ErrTypes.decryption_error)
        except GenericException as err:
            logger.error('校验签名异常, Error: %s' % err)
            exc_type, exc_value, exc_obj = sys.exc_info()
            traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
            raise GenericException(err.args[0])
        except Exception as err:
            logger.error('校验签名异常, Error: %s' % err)
            exc_type, exc_value, exc_obj = sys.exc_info()
            traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
            raise GenericException(ErrTypes.sign_validation_fail)


async def verify_signature_header(request: Request, x_xpay_signature: Annotated[str, Header()], x_algo_type: Optional[str] = Header(None)):
    logger.debug('>> verify_signature_header')
    params = []
    logger.debug('x_algo_type: %s' % x_algo_type)
    if x_xpay_signature:
        try:
            if request.method == 'GET':
                logger.debug('>> GET请求')
                params = request.query_params
                params_str = str(params)
                res = False
                if not x_algo_type or x_algo_type == 'SM':
                    res = biz_sign_util.BizSignUtil().verify_str_with_sm2(params_str, x_xpay_signature)
                elif x_algo_type == 'RSA':
                    raise GenericException(ErrTypes.unsupoorted_algo)
                else:
                    raise GenericException(ErrTypes.unsupoorted_algo)
                if res:
                    pass
                else:
                    logger.error('校验签名不通过, Error: %s' % err)
                    raise GenericException(ErrTypes.sign_validation_fail)
                logger.debug('>> 校验完成')
            elif request.method == 'POST':
                logger.debug('>> POST请求')
                params = await request.json()
                res = biz_sign_util.BizSignUtil().verify_with_sm2(params, x_xpay_signature)
                if res:
                    return x_xpay_signature
                else:
                    logger.error('校验签名不通过, Error: %s' % err)
                    raise GenericException(ErrTypes.unauth_error)
            else:
                raise GenericException(ErrTypes.unsupported_method)
        except GenericException as err:
            logger.error('校验签名异常, Error: %s' % err)
            logger.error('traceback: %s' % traceback.print_exc())
            raise GenericException(err.args[0])
        except Exception as err:
            logger.error('校验签名异常, Error: %s' % err)
            logger.error('traceback: %s' % traceback.print_exc())
            raise GenericException(ErrTypes.sign_validation_fail)
    else:
        logger.error('校验签名异常, 签名头信息为空')
        GenericException(ErrTypes.sign_validation_fail)


async def get_query_token(token: str):
    if token != "jessica":
        raise HTTPException(status_code=400, detail="No Jessica token provided")

async def get_query_token2(token: str, request: Request):
    print('>> get_query_token2')
    print('Token: %s' % request.query_params.get('token'))
    if token != "jessica":
        raise HTTPException(status_code=400, detail="No Jessica token provided")
    
class SignatureChecker:
    signature: str

    def __init__(self, x_xpay_signature: Annotated[str, Header()], request: Request):
        print('>> init SignatureChecker')
        self.request = request
        if check_is_allowed_url():
            logger.info('-------> 开放的URL')
            pass
        elif self.signature:
            self.signature = x_xpay_signature
            self.data = request.json
            print('signature: ', self.signature)
            header_keys = request.headers.keys
            logger.debug('headers: ', header_keys)
            request.headers.get('X-XPAY-Signature')
        else:
            logger.error('校验签名不通过')
            raise GenericException(ErrTypes.unauth_error)
        
def _verify_signature(data, signature):
    try:
        biz_sign_util.BizSignUtil().verify_with_sm2(data, signature)
    except Exception as err:
        logger.error('校验签名不通过, Error: %s' % err)
        raise GenericException(ErrTypes.unauth_error)

def check_is_allowed_url(request: Request):
    allowed_uris = conf.UNAUTH_URIS
    #url_split(request.url)
    is_allowed_uri = False
    url_path = request.url.path
    for url_pattern in allowed_uris:
        if url_path == url_pattern or (
            url_pattern.startswith("*") and url_path.endswith(url_pattern[1:])
        ) or (
            url_pattern.endswith("*") and url_path.startswith(url_pattern[:-1])
        ):
            is_allowed_uri = True
            logger.debug('allowed url: %s' % url_pattern)
    return is_allowed_uri

class SignatureChecker1:
    def __init__(self, valid_sign: Annotated[str, Depends(verify_signature_header)], request: Request):
        print('>> init SignatureChecker')
        self.request = request
        print('valid_sign: ', valid_sign)
        header_keys = request.headers.keys
        logger.debug('headers: ', header_keys)
        request.headers.get('X-XPAY-Signature')
        url_split(request.url)
        if not valid_sign:
            raise HTTPException(status_code=400, detail="No valid signature")


class SillyAuthChecker:
    def __init__(self, token: str, request: Request):
        print('>> init SillyAuthChecker')
        self.token = token
        self.request = request
        self.allowed_uris = conf.UNAUTH_URIS
        self.url_split(request.url)
        is_allowed_uri = False
        is_verified = False
        err_text = 'unknown error'
        url_scheme = request.url.scheme
        url_path = request.url.path
        parsed_query = parse.parse_qs(request.url.query)
        print('Token: %s' % request.query_params.get('token'))
        for url_pattern in self.allowed_uris:
            if url_path == url_pattern or (
                url_pattern.startswith("*") and url_path.endswith(url_pattern[1:])
            ) or (
                url_pattern.endswith("*") and url_path.startswith(url_pattern[:-1])
            ):
                is_allowed_uri = True
                break
            else:
                if parsed_query.get('token') and parsed_query.get('token')[0] == 'jessica':
                    is_verified = True
                else:
                    err_text = 'token有误!'
        if token != "jessica":
            raise HTTPException(status_code=400, detail="No Jessica token provided")

    def url_split(self, url):
        print('url split...')
        print('url scheme: %s' % url.scheme)
        print('url netloc: %s' % url.netloc)
        print('url port: %s' % url.port)
        print('url path: %s' % url.path)
        print('url query: %s' % url.query)

def url_split(url):
        print('url split...')
        print('url scheme: %s' % url.scheme)
        print('url netloc: %s' % url.netloc)
        print('url port: %s' % url.port)
        print('url path: %s' % url.path)
        print('url query: %s' % url.query)


########################### Deprecated ############################
async def verify_signature_header1(x_xpay_signature: Annotated[str, Header()], request: Request):
    logger.debug('>> verify_signature_header')
    if x_xpay_signature:
        try:
            biz_sign_util.BizSignUtil
        except Exception as err:
            logger.error('校验签名不通过')
            raise GenericException(ErrTypes.unauth_error)
    else:
        #raise HTTPException(status_code=403, detail="Invalid request, Forbidden")
        raise GenericException(ErrTypes.unauth_error)
        #raise exceptions.forbidden_request_exception_handler(request, HTTPException)
        return True